package executor

import (
	"fmt"

	"gitee.com/zhi/binexpr/ast"
	"gitee.com/zhi/binexpr/executor/internal/operand"
)

func wrapOperand(val any, err error) (operand.Value, error) {
	if err != nil {
		return nil, err
	}
	return operand.New(val)
}

func executeUnaryExpr(e *Executor, expr *ast.UnaryExpr, scope Scope) (any, error) {
	val, err := wrapOperand(e.Execute(expr.Expr, scope))
	if err != nil {
		return nil, err
	}
	switch expr.Operator {
	case ast.UnaryOpNegative:
		return val.Neg()
	case ast.UnaryOpInverse:
		return !val.Bool(), nil
	default:
		return nil, fmt.Errorf("unsupported unary operator: %c", expr.Operator)
	}
}

func executeOperatorExpr(e *Executor, expr *ast.OperatorExpr, scope Scope) (any, error) {
	left, err := wrapOperand(e.Execute(expr.Left, scope))
	if err != nil {
		return nil, err
	}
	right, err := e.Execute(expr.Right, scope)
	if err != nil {
		return nil, err
	}
	switch expr.Operator {
	case ast.OpTypeAdd:
		return left.Add(right)
	case ast.OpTypeSub:
		return left.Sub(right)
	case ast.OpTypeMul:
		return left.Mul(right)
	case ast.OpTypeDiv:
		return left.Div(right)
	case ast.OpTypeMod:
		return left.Mod(right)
	case ast.OpTypeEq:
		return left.Eq(right), nil
	default:
		return nil, fmt.Errorf("unknown operator: %v", expr.Operator)
	}
}
